# -*- coding: utf-8 -*-

import os
import re
import json
import logging
import datetime
import hashlib

from config import log_config

from config import config
from common import dbutil
from web_base import BaseHandler
from models.git_op import GitModel
from models.gen_rule import classify, modify_dict, to_web, add_desc, check_auto_gen
from models.paginator import Paginator
# from config.desc_dict import desc_dict
from web_base import gfuture

from tornado.web import asynchronous
from tornado.gen import coroutine


workspace = config.read_config("ENV", "workspace_path")
report_path = config.read_config("ENV", "report_path")
bakup_path = config.read_config("ENV", "bakup_path")


logger = logging.getLogger(__file__)

DB_COLLECTION = "reports"

git_log_cache = []
git_branches_cache = []
git_tags_cache = []
git_current_branch_cache = ""


class IndexHandler(BaseHandler):

    @asynchronous
    @coroutine
    def get(self):
        _r, git_key = GitModel.lock()
        if _r:
            git_client = GitModel(workspace, git_key)
            try:
                yield self.get_git_branches(git_client)
                # self.get_git_branches(git_client)
            finally:
                GitModel.unlock(git_key)
        versions = filter(lambda x: x.startswith("closure.1"), git_branches_cache)
        versions.sort(reverse=True)
        self.render("index.html", branches=git_branches_cache, tags=git_tags_cache, current_branch=git_current_branch_cache, versions=versions)

    @gfuture
    def get_git_branches(self, git_client):
        global git_tags_cache
        global git_branches_cache
        global git_current_branch_cache
        git_client.init()
        git_tags_cache = git_client.tags
        git_branches_cache = git_client.branches
        git_current_branch_cache = GitModel.get_current_branch()


class CommitHandler(BaseHandler):
    @asynchronous
    @coroutine
    def get(self):
        branch = self.get_argument("branch")
        file_path = self.get_argument("path")
        before = self.get_argument("date")
        _r, git_key = GitModel.lock()
        if _r:
            try:
                git_client = GitModel(workspace, git_key)
                cmd = 'git log --pretty=format:"%an|%ad|%s"  --date=format:"%Y/%m/%d %H:%M:%S" -5 --before="' + before + '"' + " -- " + file_path
                if branch != git_current_branch_cache:
                    ret = git_client.git_execute("git checkout " + branch)
                    if ret == "error":
                        self.write({"success": False, "msg": u"拉取提交日志失败！"})
                        return
                ret = git_client.git_execute(cmd)
                if ret != "error":
                    self.write({"success": True, "msg": ret})
                else:
                    self.write({"success": False, "msg": u"拉取提交日志失败！"})
            finally:
                GitModel.unlock(git_key)
        else:
            self.write({"success": False, "msg": u"当前git库忙，请稍后再试！"})

    @asynchronous
    @coroutine
    def post(self):
        global git_current_branch_cache
        page = int(self.get_argument("page", 1))
        branch = self.get_argument("branch")
        since = self.get_argument("since")
        before = self.get_argument("before")
        limit = self.get_argument("limit")

        _r, git_key = GitModel.lock()
        if _r:
            git_client = GitModel(workspace, git_key)
        else:
            if branch == GitModel.get_current_branch() and since == before == limit == "":
                logs, paginator = Paginator(git_log_cache, page, 25).to_dict()
                self.render("list/git_log_list.html", logs=logs, paginator=paginator, current_branch=git_current_branch_cache)
            else:
                self.write({"success": False, "msg": u"当前git库忙，请稍后再试！"})
            return
        try:
            yield self.get_git_logs(git_client, branch, since, before, limit)
            # self.get_git_logs(git_client, branch, since, before, limit)

            logs, paginator = Paginator(git_log_cache, page, 25).to_dict()

            self.render("list/git_log_list.html", logs=logs, paginator=paginator, current_branch=git_current_branch_cache)
        except Exception as e:
            logger.exception(e)
            self.write({"success": False, "msg": u"当前git库忙，请稍后再试！"})
        finally:
            GitModel.unlock(git_key)

    @gfuture
    def get_git_logs(self, git_client, branch, since, before, limit):
        git_client.init()
        _since = None
        _before = None
        if since == before == "":
            limit = limit if limit else 100
        else:
            limit = limit if limit else 0
            tmp = since.split("/")
            if len(tmp) == 3:
                _since = tmp[2] + "-" + tmp[0] + "-" + tmp[1]
            tmp = before.split("/")
            if len(tmp) == 3:
                _before = tmp[2] + "-" + tmp[0] + "-" + tmp[1]
        commits = git_client.update_commits(branch, _since, _before, limit=limit)
        commits.sort(lambda x, y: cmp(x["Date"], y["Date"]), reverse=True)
        global git_log_cache
        global git_current_branch_cache
        git_log_cache = commits
        git_current_branch_cache = branch


class ReportHandler(BaseHandler):

    @asynchronous
    @coroutine
    def get(self):
        report_id = self.get_argument("key")
        report = dbutil.mg_query(DB_COLLECTION, {"report_id": report_id}, {"report": 0, "_id": 0})
        if report.count() > 0:
            self.render("list/tree_list.html", report_id=report_id, report=report[0])
        else:
            self.write("报告不存在！")

    @asynchronous
    @coroutine
    def post(self):
        operation = self.get_argument("op")
        if "report_list" == operation:
            page = int(self.get_argument("page", 1))

            report_list = []
            reports = yield self.load_reports_db()
            # reports = self.load_reports_db()

            for report in reports:
                report_list.append(report)

            report_list.sort(lambda x, y: cmp(x["date"], y["date"]), reverse=True)
            report_page, paginator = Paginator(report_list, page, 15).to_dict()
            self.render("list/report_list.html", report_list=report_page, paginator=paginator)

        elif "delete" == operation:
            report_id = self.get_argument("id")

            try:
                dbutil.mg_delete(DB_COLLECTION, {"report_id": report_id})
                success = True
            except Exception as e:
                logger.error(e)
                success = False
            self.write({"success": success, "msg": ""})

        elif "gen_report" == operation:
            self.session["progress"] = {"step": "0", "progress": 1, "state": "start", "msg": ""}
            _r, git_key = GitModel.lock()
            if _r:
                git_client = GitModel(workspace, git_key)
            else:
                self.write({"success": False, "msg": u"当前git库忙，请稍后再试！"})
                return
            try:
                success, msg = yield self.git_report(git_client)
                # success, msg = self.git_report(git_client)

                self.write({"success": success, "msg": msg})
            except Exception as e:
                logger.exception(e)
                self.write({"success": False, "msg": u"生成报告失败！"})
            finally:
                self.session["progress"] = {"step": "1/7", "progress": 0, "state": "start", "msg": ""}
                GitModel.unlock(git_key)

    @gfuture
    def load_reports_db(self):
        reports = dbutil.mg_query("reports", {}, {"report": 0, "_id": 0})
        return reports

    @gfuture
    def git_report(self, git_client):
        global git_current_branch_cache
        git_client.init()
        mode = self.get_argument("mode")
        section1 = self.get_argument("section1")
        section2 = self.get_argument("section2")
        section1_info = self.get_argument("section1_info")
        section2_info = self.get_argument("section2_info")
        section1_branch = self.get_argument("section1_branch")

        # 提取指纹
        if mode == "1":
            section1_branch = section1
            try:
                logger.info(u"提取分支2 Head 指纹.......")
                self.session["progress"] = {"step": "1/7", "progress": 1, "state": "start", "msg": u"提取分支2 Head 指纹......."}

                git_client.update_branches()
                commit_log = git_client.update_commits(section2, since="", limit=1)
                if len(commit_log) == 0:
                    self.session["progress"] = {"step": "1/7", "progress": 0, "state": "start", "msg": ""}
                    return False, u"提取分支2Head处commitID失败！"

                git_current_branch_cache = section2
                commit_id2 = commit_log[0]["CommitId"]
                section2_info = section2 + "(" + commit_log[0]['Date'] + ' | ' + commit_log[0]['Author'] + ' | ' + commit_log[0]['message'] + ")"

                logger.info(u"end")
                self.session["progress"] = {"step": "1/7", "progress": 20, "state": "end", "msg": u"提取分支2 Head 指纹......."}

                logger.info(u"提取分支1 Head 指纹.......")
                self.session["progress"] = {"step": "2/7", "progress": 21, "state": "start", "msg": u"提取分支1 Head 指纹......."}

                git_client.update_branches()
                commit_log = git_client.update_commits(section1, since="", limit=1)
                if len(commit_log) == 0:
                    self.session["progress"] = {"step": "1/7", "progress": 0, "state": "start", "msg": ""}
                    return False, u"提取分支1Head处commitID失败！"

                git_current_branch_cache = section1
                commit_id1 = commit_log[0]["CommitId"]
                section1_info = section1 + "(" + commit_log[0]['Date'] + ' | ' + commit_log[0]['Author'] + ' | ' + commit_log[0]['message'] + ")"

                logger.info(u"end")
                self.session["progress"] = {"step": "2/7", "progress": 40, "state": "end", "msg": u"提取分支1 Head 指纹......."}
            except Exception as e:
                logger.exception(e)
                self.session["progress"] = {"step": "1/7", "progress": 0, "state": "start", "msg": ""}
                return False, u"提取分支Head处commitID失败！"
        else:
            commit_id1 = section1
            commit_id2 = section2

        logger.info(u"提取更改文件列表.......")
        self.session["progress"] = {"step": "3/7", "progress": 41, "state": "start", "msg": u"提取更改文件列表......."}
        report_data = {
            u"英雄": {
                u"展示英雄": {},
                u"战斗内英雄": {},
            },
            u"场景": {u"展示场景": {},
                      u"魔方、卡牌、宝石": {},
                      u"展示场景组件": {},
                      u"5v5场景": {}},
            u"UI": {},
            u"通用": {}
        }

        # 拉取git提交历史
        files = git_client.get_diff(commit_id1, commit_id2)

        print "total files: ", len(files)
        logger.info("end")
        self.session["progress"] = {"step": "3/7", "progress": 50, "state": "end", "msg": u"提取更改文件列表......."}

        logger.info(u"提取文件最后修改人......")
        self.session["progress"] = {"step": "4/7", "progress": 50, "state": "start", "msg": u"提取文件最后修改人......."}

        authors = {}
        parent = git_client.get_parent(commit_id1, commit_id2)
        if parent != "" and parent != "error":
            since_date = git_client.get_commit_date(parent)
            if since_date != "" and since_date != "error":
                since_date = date_math(since_date.split(" ")[0], -20) + " " + since_date.split(" ")[1]
                author_log = git_client.get_author_log(since_date)
                if author_log != "error":
                    _author = ""
                    count = 0
                    _logs = author_log.split("\n")
                    total = len(_logs)
                    for line in _logs:
                        line = line.strip()
                        if line.startswith("### "):
                            _author = line.strip("### ")
                        elif line.startswith("_MobaGoArt/Assets/") and line not in authors:
                            authors[line] = _author
                        count += 1
                        if count % 1000 == 0:
                            self.session["progress"] = {"step": "4/7", "progress": round(15 * count / total, 2) + 50, "state": "start", "msg": u"提取文件最后修改人......."}

        count = 0
        last_file = list(set(files).difference(set(authors.keys())))
        total = len(last_file)
        # print total
        for line in last_file:
            author = git_client.get_author(git_current_branch_cache, line)
            if author == "error" or author == "":
                author = "||"
            authors[line] = author
            count += 1
            if count % 10 == 0:
                self.session["progress"] = {"step": "4/7", "progress": round(20 * count / total, 2) + 65, "state": "start", "msg": u"提取文件最后修改人......."}

        logger.info("end")
        self.session["progress"] = {"step": "4/7", "progress": 85, "state": "end", "msg": u"提取文件最后修改人......."}

        # 文件归类整理
        logger.info(u"文件归类......")
        self.session["progress"] = {"step": "5/7", "progress": 85, "state": "start", "msg": u"文件归类......."}

        files.sort()
        lines_report, no_matched = classify(files, authors)

        # with open("d:/modify_dict.log", "w") as fp:
        #     fp.write(json.dumps(lines_report).decode("unicode-escape").encode("utf8"))

        total = len(lines_report)
        count = 0
        for line in lines_report:
            seg = line["segment"].split("|")
            ap_msg = u"_设置修改" if line["meta"] else ""
            author = line["author"]
            full_path = line["full_path"]
            modify_dict(seg, report_data, ap_msg, author, full_path)
            count += 1
            if count % 100 == 0:
                self.session["progress"] = {"step": "5/7", "progress": round(5 * count / total, 2) + 85, "state": "start", "msg": u"文件归类......."}

        logger.info("end")
        self.session["progress"] = {"step": "5/7", "progress": 90, "state": "end", "msg": u"文件归类......."}

        logger.info(u"转为树表格式......")
        self.session["progress"] = {"step": "6/7", "progress": 91, "state": "start", "msg": u"转为树表格式......."}

        result = []
        for root, info in report_data.items():
            child = {}
            to_web(root, info, 1, child)
            if root == u"英雄":
                if "children" in child:
                    for children in child["children"]:
                        if "children" in children:
                            children["children"].sort(lambda x, y: cmp(x["title"], y["title"]))
            result.append(child)

        logger.info("end")
        self.session["progress"] = {"step": "6/7", "progress": 95, "state": "end", "msg": u"转为树表格式......."}

        # 自动生成文件检查
        auto_gen = check_auto_gen(files, authors)

        logger.info("save to db......")
        self.session["progress"] = {"step": "7/7", "progress": 96, "state": "start", "msg": u"save to db......."}

        _now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        md5 = hashlib.md5()
        md5.update(commit_id1 + commit_id2 + _now)
        report_id = md5.hexdigest()

        report = {"date": _now,
                  "section1": commit_id1,
                  "section2": commit_id2,
                  "section1_info": section1_info,
                  "section2_info": section2_info,
                  "section1_branch": section1_branch,
                  "report_id": report_id,
                  "report": result,
                  "no_matched": no_matched,
                  "auto_gen": auto_gen}

        try:
            dbutil.mg_insert(DB_COLLECTION, report)
            success = True
            msg = ""
        except Exception as e:
            logger.error(e.message.decode("unicode-escape").encode("utf8"))
            logger.exception(e)
            success = False
            msg = u"写入数据库失败！"
            with open("d:/" + report_id, "w") as fp:
                fp.write(json.dumps(report).decode("unicode-escape").encode("utf8"))

        logger.info("end")
        self.session["progress"] = {"step": "7/7", "progress": 100, "state": "end", "msg": u"save to db......."}

        return success, msg


class ReportShowHandler(BaseHandler):
    @asynchronous
    @coroutine
    def get(self):
        report_id = self.get_argument("key")
        report_type = self.get_argument("type")
        if report_type == "master":
            desc_dict = {}
            ret = dbutil.mg_query(DB_COLLECTION, {"report_id": report_id}, {"report": 1, "_id": 0})
            try:
                desc_dict = dbutil.mg_query("reports_desc", {})[0]
            except:
                pass
            if ret.count() > 0:
                report = ret[0]["report"]
                if len(desc_dict) > 0:
                    add_desc(report, desc_dict)
                self.write(json.dumps(report))
            else:
                self.write({})
        elif report_type == "auto_gen":
            ret = dbutil.mg_query(DB_COLLECTION, {"report_id": report_id}, {"auto_gen": 1, "_id": 0})
            if ret.count() > 0:
                report = ret[0]["auto_gen"]
                self.write(json.dumps(report))
            else:
                self.write({})


class ProgressHandler(BaseHandler):
    @asynchronous
    @coroutine
    def get(self):
        if "progress" in self.session:
            progress = self.session["progress"]
            # print progress
        else:
            progress = {"day": 0, "progress": 100, "state": "end"}
        self.write(progress)


class DescHandler(BaseHandler):
    def post(self):
        tree_path = self.get_argument("tree_path")
        new_desc = self.get_argument("new_desc")
        if tree_path:
            nodes = tree_path.split("$")
            keys = []
            for node in nodes:
                if "(" in node and ")" in node:
                    node = node.split("(")[0].strip()
                if "." in node:
                    node = node.replace(".", "?")
                keys.append(node)
            keys.append("_desc")

            try:
                dbutil.mg_update("reports_desc", {}, {"$set": {".".join(keys): new_desc.strip()}})
                success = True
                msg = "更新成功"
            except Exception as e:
                logger.error(e.message)
                success = False
                msg = e.message

        else:
            success = False
            msg = "路径不能为空！"

        self.write({"success": success, "msg": msg})


def date_math(date, operator):
    """
    增减天
    :param date:
    :param operator:
    :return:
    """
    date_reg = date.split("-")
    date_ob = datetime.date(year=int(date_reg[0]), month=int(date_reg[1]), day=int(date_reg[2]))
    return (date_ob + datetime.timedelta(days=operator)).strftime("%Y-%m-%d")
